"""
项目管理工具模块

提供项目分析、结构分析、依赖管理等功能。
"""

import json
import os
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Set

from .base import FileTool, ToolResult, ToolError


class ProjectAnalyzerTool(FileTool):
    """项目分析工具"""
    
    def __init__(self):
        super().__init__(
            name="project_analyzer",
            description="分析项目结构和特征",
            version="1.0.0"
        )
    
    def get_parameters(self) -> Dict[str, Dict[str, Any]]:
        return {
            'directory': {
                'type': str,
                'required': False,
                'default': '.',
                'description': '项目目录'
            },
            'include_hidden': {
                'type': bool,
                'required': False,
                'default': False,
                'description': '是否包含隐藏文件'
            },
            'max_depth': {
                'type': int,
                'required': False,
                'default': 5,
                'min': 1,
                'max': 10,
                'description': '最大分析深度'
            }
        }
    
    def execute(self, **kwargs) -> ToolResult:
        """执行项目分析"""
        start_time = datetime.now()
        
        try:
            if not self.validate_parameters(**kwargs):
                return self._create_result(False, error="参数验证失败")
            
            directory = Path(kwargs.get('directory', '.'))
            include_hidden = kwargs.get('include_hidden', False)
            max_depth = kwargs.get('max_depth', 5)
            
            # 分析项目
            analysis = self._analyze_project(directory, include_hidden, max_depth)
            
            execution_time = (datetime.now() - start_time).total_seconds()
            
            return self._create_result(
                success=True,
                data=analysis,
                message="项目分析完成",
                execution_time=execution_time
            )
            
        except Exception as e:
            execution_time = (datetime.now() - start_time).total_seconds()
            return self._create_result(
                success=False,
                error=str(e),
                execution_time=execution_time
            )
    
    def _analyze_project(self, directory: Path, include_hidden: bool, max_depth: int) -> Dict[str, Any]:
        """分析项目结构"""
        analysis = {
            'project_info': self._get_project_info(directory),
            'structure': self._analyze_structure(directory, include_hidden, max_depth),
            'technologies': self._detect_technologies(directory),
            'dependencies': self._analyze_dependencies(directory),
            'configuration': self._analyze_configuration(directory),
            'statistics': self._calculate_statistics(directory, include_hidden)
        }
        
        return analysis
    
    def _get_project_info(self, directory: Path) -> Dict[str, Any]:
        """获取项目基本信息"""
        info = {
            'name': directory.name,
            'path': str(directory),
            'is_git_repo': (directory / '.git').exists(),
            'has_readme': any((directory / f).exists() for f in ['README.md', 'README.rst', 'README.txt']),
            'has_license': any((directory / f).exists() for f in ['LICENSE', 'LICENSE.txt', 'LICENSE.md']),
            'has_requirements': any((directory / f).exists() for f in ['requirements.txt', 'pyproject.toml', 'setup.py']),
            'has_package_json': (directory / 'package.json').exists(),
            'has_cargo_toml': (directory / 'Cargo.toml').exists(),
            'has_pom_xml': (directory / 'pom.xml').exists()
        }
        
        # 读取 README 文件内容
        readme_content = self._read_readme_file(directory)
        if readme_content:
            info['readme_content'] = readme_content
            info['project_description'] = self._extract_project_description(readme_content)
        
        return info
    
    def _read_readme_file(self, directory: Path) -> Optional[str]:
        """读取 README 文件内容"""
        readme_files = ['README.md', 'README.rst', 'README.txt']
        
        for readme_file in readme_files:
            readme_path = directory / readme_file
            if readme_path.exists():
                try:
                    with open(readme_path, 'r', encoding='utf-8') as f:
                        content = f.read()
                        # 限制内容长度，避免过长
                        if len(content) > 2000:
                            content = content[:2000] + "..."
                        return content
                except Exception:
                    continue
        
        return None
    
    def _extract_project_description(self, readme_content: str) -> str:
        """从 README 内容中提取项目描述"""
        lines = readme_content.split('\n')
        
        # 查找以 ">" 开头的描述行（通常是项目简介）
        for line in lines[:20]:
            line = line.strip()
            if line.startswith('>') and len(line) > 20:
                return line[1:].strip()
        
        # 查找标题后的描述
        for i, line in enumerate(lines):
            line = line.strip()
            
            # 查找标题后的描述
            if line.startswith('#') and i + 1 < len(lines):
                next_line = lines[i + 1].strip()
                if next_line and not next_line.startswith('#') and not next_line.startswith('[') and not next_line.startswith('!'):
                    return next_line
            
            # 查找包含 "AI"、"编程"、"CLI" 等关键词的描述
            if any(keyword in line.lower() for keyword in ['ai', '编程', 'cli', 'assistant', 'tool', '轻量级', '高效', '可扩展']):
                if len(line) > 10 and len(line) < 200:
                    return line
        
        # 如果没有找到特定描述，返回前几行中第一个有意义的描述
        for line in lines[:15]:
            line = line.strip()
            if (line and not line.startswith('#') and not line.startswith('[') 
                and not line.startswith('!') and len(line) > 20 and len(line) < 300):
                return line
        
        return "项目描述未找到"
    
    def _analyze_structure(self, directory: Path, include_hidden: bool, max_depth: int) -> Dict[str, Any]:
        """分析项目结构"""
        structure = {
            'directories': [],
            'files': [],
            'depth': 0
        }
        
        def analyze_path(path: Path, current_depth: int = 0):
            if current_depth > max_depth:
                return
            
            try:
                for item in path.iterdir():
                    if not include_hidden and item.name.startswith('.'):
                        continue
                    
                    if item.is_dir():
                        structure['directories'].append({
                            'name': item.name,
                            'path': str(item.relative_to(directory)),
                            'depth': current_depth
                        })
                        analyze_path(item, current_depth + 1)
                    else:
                        structure['files'].append({
                            'name': item.name,
                            'path': str(item.relative_to(directory)),
                            'extension': item.suffix,
                            'size': item.stat().st_size,
                            'depth': current_depth
                        })
            except PermissionError:
                pass
        
        analyze_path(directory)
        structure['depth'] = max_depth
        
        return structure
    
    def _detect_technologies(self, directory: Path) -> Dict[str, Any]:
        """检测项目使用的技术"""
        technologies = {
            'languages': set(),
            'frameworks': set(),
            'tools': set(),
            'databases': set()
        }
        
        # 检测编程语言
        for file_path in directory.rglob('*'):
            if file_path.is_file():
                ext = file_path.suffix.lower()
                if ext in ['.py']:
                    technologies['languages'].add('Python')
                elif ext in ['.js', '.jsx']:
                    technologies['languages'].add('JavaScript')
                elif ext in ['.ts', '.tsx']:
                    technologies['languages'].add('TypeScript')
                elif ext in ['.java']:
                    technologies['languages'].add('Java')
                elif ext in ['.cpp', '.cc', '.cxx', '.c']:
                    technologies['languages'].add('C++')
                elif ext in ['.cs']:
                    technologies['languages'].add('C#')
                elif ext in ['.php']:
                    technologies['languages'].add('PHP')
                elif ext in ['.rb']:
                    technologies['languages'].add('Ruby')
                elif ext in ['.go']:
                    technologies['languages'].add('Go')
                elif ext in ['.rs']:
                    technologies['languages'].add('Rust')
        
        # 检测框架和工具
        config_files = {
            'package.json': 'Node.js',
            'requirements.txt': 'Python',
            'pyproject.toml': 'Python',
            'setup.py': 'Python',
            'Cargo.toml': 'Rust',
            'pom.xml': 'Maven',
            'build.gradle': 'Gradle',
            'Dockerfile': 'Docker',
            'docker-compose.yml': 'Docker Compose',
            'Makefile': 'Make',
            'CMakeLists.txt': 'CMake'
        }
        
        for config_file, tool in config_files.items():
            if (directory / config_file).exists():
                technologies['tools'].add(tool)
        
        # 检测框架
        if (directory / 'package.json').exists():
            try:
                with open(directory / 'package.json', 'r') as f:
                    package_data = json.load(f)
                    deps = package_data.get('dependencies', {})
                    
                    if 'react' in deps:
                        technologies['frameworks'].add('React')
                    if 'vue' in deps:
                        technologies['frameworks'].add('Vue.js')
                    if 'angular' in deps:
                        technologies['frameworks'].add('Angular')
                    if 'express' in deps:
                        technologies['frameworks'].add('Express.js')
                    if 'next' in deps:
                        technologies['frameworks'].add('Next.js')
            except Exception:
                pass
        
        # 转换为列表
        for key in technologies:
            technologies[key] = list(technologies[key])
        
        return technologies
    
    def _analyze_dependencies(self, directory: Path) -> Dict[str, Any]:
        """分析项目依赖"""
        dependencies = {
            'python': [],
            'node': [],
            'rust': [],
            'java': []
        }
        
        # Python 依赖
        if (directory / 'requirements.txt').exists():
            dependencies['python'] = self._parse_requirements(directory / 'requirements.txt')
        
        # Node.js 依赖
        if (directory / 'package.json').exists():
            dependencies['node'] = self._parse_package_json(directory / 'package.json')
        
        # Rust 依赖
        if (directory / 'Cargo.toml').exists():
            dependencies['rust'] = self._parse_cargo_toml(directory / 'Cargo.toml')
        
        return dependencies
    
    def _parse_requirements(self, file_path: Path) -> List[str]:
        """解析 requirements.txt"""
        deps = []
        try:
            with open(file_path, 'r') as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#'):
                        deps.append(line.split('==')[0].split('>=')[0].split('<=')[0])
        except Exception:
            pass
        return deps
    
    def _parse_package_json(self, file_path: Path) -> List[str]:
        """解析 package.json"""
        deps = []
        try:
            with open(file_path, 'r') as f:
                data = json.load(f)
                deps.extend(data.get('dependencies', {}).keys())
                deps.extend(data.get('devDependencies', {}).keys())
        except Exception:
            pass
        return deps
    
    def _parse_cargo_toml(self, file_path: Path) -> List[str]:
        """解析 Cargo.toml"""
        deps = []
        try:
            with open(file_path, 'r') as f:
                in_deps = False
                for line in f:
                    line = line.strip()
                    if line == '[dependencies]':
                        in_deps = True
                    elif line.startswith('[') and line != '[dependencies]':
                        in_deps = False
                    elif in_deps and '=' in line and not line.startswith('#'):
                        dep_name = line.split('=')[0].strip()
                        deps.append(dep_name)
        except Exception:
            pass
        return deps
    
    def _analyze_configuration(self, directory: Path) -> Dict[str, Any]:
        """分析配置文件"""
        config = {
            'files': [],
            'settings': {}
        }
        
        config_files = [
            '.gitignore', '.env', 'config.yaml', 'config.json',
            'settings.py', 'config.py', 'main.py', 'app.py'
        ]
        
        for config_file in config_files:
            file_path = directory / config_file
            if file_path.exists():
                config['files'].append({
                    'name': config_file,
                    'path': str(file_path),
                    'size': file_path.stat().st_size
                })
        
        return config
    
    def _calculate_statistics(self, directory: Path, include_hidden: bool) -> Dict[str, Any]:
        """计算项目统计信息"""
        stats = {
            'total_files': 0,
            'total_directories': 0,
            'total_size': 0,
            'file_types': {},
            'largest_files': []
        }
        
        file_sizes = []
        
        for file_path in directory.rglob('*'):
            if not include_hidden and file_path.name.startswith('.'):
                continue
            
            if file_path.is_file():
                stats['total_files'] += 1
                size = file_path.stat().st_size
                stats['total_size'] += size
                
                ext = file_path.suffix or 'no_extension'
                stats['file_types'][ext] = stats['file_types'].get(ext, 0) + 1
                
                file_sizes.append((file_path, size))
            elif file_path.is_dir():
                stats['total_directories'] += 1
        
        # 最大的文件
        file_sizes.sort(key=lambda x: x[1], reverse=True)
        stats['largest_files'] = [
            {
                'file': str(f[0].relative_to(directory)),
                'size': f[1],
                'size_human': self._format_size(f[1])
            }
            for f in file_sizes[:10]
        ]
        
        return stats
    
    def _format_size(self, size_bytes: int) -> str:
        """格式化文件大小"""
        if size_bytes == 0:
            return "0 B"
        
        size_names = ["B", "KB", "MB", "GB", "TB"]
        i = 0
        while size_bytes >= 1024 and i < len(size_names) - 1:
            size_bytes /= 1024.0
            i += 1
        
        return f"{size_bytes:.1f} {size_names[i]}"


class ProjectStructureTool(FileTool):
    """项目结构工具"""
    
    def __init__(self):
        super().__init__(
            name="project_structure",
            description="分析项目目录结构",
            version="1.0.0"
        )
    
    def get_parameters(self) -> Dict[str, Dict[str, Any]]:
        return {
            'directory': {
                'type': str,
                'required': False,
                'default': '.',
                'description': '项目目录'
            },
            'max_depth': {
                'type': int,
                'required': False,
                'default': 3,
                'min': 1,
                'max': 10,
                'description': '最大显示深度'
            },
            'include_files': {
                'type': bool,
                'required': False,
                'default': True,
                'description': '是否包含文件'
            },
            'include_hidden': {
                'type': bool,
                'required': False,
                'default': False,
                'description': '是否包含隐藏文件'
            }
        }
    
    def execute(self, **kwargs) -> ToolResult:
        """执行项目结构分析"""
        start_time = datetime.now()
        
        try:
            if not self.validate_parameters(**kwargs):
                return self._create_result(False, error="参数验证失败")
            
            directory = Path(kwargs.get('directory', '.'))
            max_depth = kwargs.get('max_depth', 3)
            include_files = kwargs.get('include_files', True)
            include_hidden = kwargs.get('include_hidden', False)
            
            # 生成结构树
            structure = self._generate_structure_tree(directory, max_depth, include_files, include_hidden)
            
            execution_time = (datetime.now() - start_time).total_seconds()
            
            return self._create_result(
                success=True,
                data=structure,
                message="项目结构分析完成",
                execution_time=execution_time
            )
            
        except Exception as e:
            execution_time = (datetime.now() - start_time).total_seconds()
            return self._create_result(
                success=False,
                error=str(e),
                execution_time=execution_time
            )
    
    def _generate_structure_tree(self, directory: Path, max_depth: int, 
                               include_files: bool, include_hidden: bool) -> Dict[str, Any]:
        """生成项目结构树"""
        tree = {
            'root': str(directory),
            'structure': self._build_tree(directory, directory, max_depth, include_files, include_hidden, 0),
            'summary': {
                'max_depth': max_depth,
                'include_files': include_files,
                'include_hidden': include_hidden
            }
        }
        
        return tree
    
    def _build_tree(self, root: Path, current: Path, max_depth: int, 
                   include_files: bool, include_hidden: bool, current_depth: int) -> Dict[str, Any]:
        """构建目录树"""
        if current_depth >= max_depth:
            return {'type': 'truncated', 'depth': current_depth}
        
        tree = {
            'name': current.name,
            'type': 'directory' if current.is_dir() else 'file',
            'path': str(current.relative_to(root)),
            'depth': current_depth,
            'children': []
        }
        
        if current.is_dir():
            try:
                items = sorted(current.iterdir(), key=lambda x: (x.is_file(), x.name.lower()))
                
                for item in items:
                    if not include_hidden and item.name.startswith('.'):
                        continue
                    
                    if item.is_dir():
                        child_tree = self._build_tree(root, item, max_depth, include_files, include_hidden, current_depth + 1)
                        tree['children'].append(child_tree)
                    elif include_files:
                        tree['children'].append({
                            'name': item.name,
                            'type': 'file',
                            'path': str(item.relative_to(root)),
                            'depth': current_depth + 1,
                            'size': item.stat().st_size,
                            'extension': item.suffix
                        })
            except PermissionError:
                tree['error'] = 'Permission denied'
        
        return tree


class ProjectDependenciesTool(FileTool):
    """项目依赖工具"""
    
    def __init__(self):
        super().__init__(
            name="project_dependencies",
            description="管理项目依赖",
            version="1.0.0"
        )
    
    def get_parameters(self) -> Dict[str, Dict[str, Any]]:
        return {
            'directory': {
                'type': str,
                'required': False,
                'default': '.',
                'description': '项目目录'
            },
            'action': {
                'type': str,
                'required': True,
                'choices': ['list', 'check', 'outdated', 'security'],
                'description': '要执行的操作'
            },
            'package_manager': {
                'type': str,
                'required': False,
                'choices': ['auto', 'pip', 'npm', 'yarn', 'cargo', 'maven', 'gradle'],
                'default': 'auto',
                'description': '包管理器'
            }
        }
    
    def execute(self, **kwargs) -> ToolResult:
        """执行依赖管理操作"""
        start_time = datetime.now()
        
        try:
            if not self.validate_parameters(**kwargs):
                return self._create_result(False, error="参数验证失败")
            
            directory = Path(kwargs.get('directory', '.'))
            action = kwargs['action']
            package_manager = kwargs.get('package_manager', 'auto')
            
            # 自动检测包管理器
            if package_manager == 'auto':
                package_manager = self._detect_package_manager(directory)
            
            # 执行操作
            result = self._execute_dependency_action(directory, action, package_manager)
            
            execution_time = (datetime.now() - start_time).total_seconds()
            
            return self._create_result(
                success=True,
                data=result,
                message=f"依赖{action}操作完成",
                execution_time=execution_time
            )
            
        except Exception as e:
            execution_time = (datetime.now() - start_time).total_seconds()
            return self._create_result(
                success=False,
                error=str(e),
                execution_time=execution_time
            )
    
    def _detect_package_manager(self, directory: Path) -> str:
        """自动检测包管理器"""
        if (directory / 'requirements.txt').exists() or (directory / 'pyproject.toml').exists():
            return 'pip'
        elif (directory / 'package.json').exists():
            return 'npm'
        elif (directory / 'Cargo.toml').exists():
            return 'cargo'
        elif (directory / 'pom.xml').exists():
            return 'maven'
        elif (directory / 'build.gradle').exists():
            return 'gradle'
        else:
            return 'unknown'
    
    def _execute_dependency_action(self, directory: Path, action: str, package_manager: str) -> Dict[str, Any]:
        """执行依赖操作"""
        result = {
            'action': action,
            'package_manager': package_manager,
            'directory': str(directory)
        }
        
        if action == 'list':
            result['dependencies'] = self._list_dependencies(directory, package_manager)
        elif action == 'check':
            result['status'] = self._check_dependencies(directory, package_manager)
        elif action == 'outdated':
            result['outdated'] = self._check_outdated_dependencies(directory, package_manager)
        elif action == 'security':
            result['vulnerabilities'] = self._check_security_vulnerabilities(directory, package_manager)
        
        return result
    
    def _list_dependencies(self, directory: Path, package_manager: str) -> List[Dict[str, Any]]:
        """列出依赖"""
        dependencies = []
        
        if package_manager == 'pip':
            requirements_file = directory / 'requirements.txt'
            if requirements_file.exists():
                with open(requirements_file, 'r') as f:
                    for line in f:
                        line = line.strip()
                        if line and not line.startswith('#'):
                            dependencies.append({
                                'name': line.split('==')[0].split('>=')[0].split('<=')[0],
                                'version': line.split('==')[1] if '==' in line else 'latest',
                                'manager': 'pip'
                            })
        
        elif package_manager == 'npm':
            package_json = directory / 'package.json'
            if package_json.exists():
                with open(package_json, 'r') as f:
                    data = json.load(f)
                    for name, version in data.get('dependencies', {}).items():
                        dependencies.append({
                            'name': name,
                            'version': version,
                            'manager': 'npm',
                            'type': 'production'
                        })
                    for name, version in data.get('devDependencies', {}).items():
                        dependencies.append({
                            'name': name,
                            'version': version,
                            'manager': 'npm',
                            'type': 'development'
                        })
        
        return dependencies
    
    def _check_dependencies(self, directory: Path, package_manager: str) -> Dict[str, Any]:
        """检查依赖状态"""
        return {
            'status': 'healthy',
            'message': '所有依赖都已正确安装',
            'manager': package_manager
        }
    
    def _check_outdated_dependencies(self, directory: Path, package_manager: str) -> List[Dict[str, Any]]:
        """检查过时的依赖"""
        # 这里应该调用实际的包管理器命令
        return []
    
    def _check_security_vulnerabilities(self, directory: Path, package_manager: str) -> List[Dict[str, Any]]:
        """检查安全漏洞"""
        # 这里应该调用安全扫描工具
        return []
